package self;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.ZParams;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by 刘万祥 on 2017/5/14 0014.
 */
public class Chapter06 {

    private final String recent_key_prefix_list = "recent:";
    private final String lock_key_prefix = "lock:";
    private final String semaphore_key_prefix = "semaphore:remote";


    public static void main(String[] args) {
        new Chapter06().run();
    }

    private void run() {
        Jedis conn = new Jedis("localhost");
        conn.select(15);

        addUpdateContact(conn);




    }

    private void addUpdateContact(Jedis conn) {
        String user = "userX";
        String recentKey = recent_key_prefix_list + user;

        Pipeline pipeline = conn.pipelined();

        for (int i = 30; i < 40; i++) {
            String contact = "133788588"+i;
            pipeline.lrem(recentKey, 0, contact);
            pipeline.lpush(recentKey, contact);
            pipeline.ltrim(recentKey, 0, 99);

        }
        pipeline.sync();

        List<String> recents = conn.lrange(recent_key_prefix_list + "userX", 0, -1);
        for (String recent : recents) {
            System.out.println("联系人: "+recent);
        }

        fetchAutoCompletedList(conn, user, "133");

    }

    private List<String > fetchAutoCompletedList(Jedis  conn,String user,String prefix) {
        List<String> exists = conn.lrange(recent_key_prefix_list + user, 0, -1);
        List<String> matches = new ArrayList<>();

        for (String exist : exists) {
            if (exist.toLowerCase().startsWith(prefix)) {
                matches.add(exist);
            }
        }

        return matches;
    }


    private String  acquireLock(Jedis conn, String lockName) {
        return acquireLock(conn, lockName, 10000);
    }

    private String  acquireLock(Jedis conn, String lockName, int acquireTimeout) {

        long end = System.currentTimeMillis() + acquireTimeout;
        String id = UUID.randomUUID().toString();
        while (System.currentTimeMillis() < end) {
            if (conn.setnx(lock_key_prefix + lockName, id) == 1) {
                return  id;
            }
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }


        return null;
    }

    private boolean releaseLock(Jedis conn, String lockName, String id) {
        String lockKey = lock_key_prefix + lockName;

        while (true) {
            conn.watch(lockKey);

            if (id.equals(conn.get(lockKey))) {
                Transaction trans = conn.multi();
                trans.del(lockKey);

                List<Object> results = trans.exec();
                if (results == null) {
                    continue;
                }
                return true;
            }

            conn.unwatch();
            break;

        }

        return false;
    }

    private String  acquireLockWithTimeout(Jedis   conn,String lockName,int acquireTimeout,int expireTimeout) {
        String lockKey = lock_key_prefix + lockName;
        String id = UUID.randomUUID().toString();
        int expireSeconds = expireTimeout / 1000;
        long end = System.currentTimeMillis() + acquireTimeout;

        while (System.currentTimeMillis() < end) {
            if (conn.setnx(lockKey, id) == 1) {
                conn.expire(lockKey, expireSeconds);
                return id;
            }

            if (conn.ttl(lockKey) == -1) {
                conn.expire(lockKey, expireSeconds);
            }

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }

        return null;
    }

    private String  acquireFairSemaphore(Jedis conn, long timeout, long limit) {
        String id = UUID.randomUUID().toString();
        String owner = semaphore_key_prefix + ":owner";
        String counter = semaphore_key_prefix + ":counter";

        long now = System.currentTimeMillis();
        Transaction trans = conn.multi();
//      从超时有序集合里  移除信号超时的
        trans.zremrangeByScore(semaphore_key_prefix, "-inf", String.valueOf(now - timeout));
        ZParams zParams = new ZParams();
        zParams.weightsByDouble(1, 0);
//      对超时有序集合和信号量拥有者执行交集计算,结果保存到信号量拥有者有序集合里面
        trans.zinterstore(owner, zParams, owner, semaphore_key_prefix);
        trans.incr(counter);

        List<Object> results = trans.exec();
        Long autoNumber = (Long) results.get(results.size() - 1);

        trans = conn.multi();
        trans.zadd(semaphore_key_prefix, now, id);
        trans.zadd(owner, autoNumber, id);
        trans.zrank(owner, id);
        results = trans.exec();

        long result=(Long) results.get(results.size() - 1);
//        通过排名来判断客户端是否取得了信号量,当排名小于最大值时,获取到信号量
        if (result < limit) {
            return id;
        }

        trans = conn.multi();
        trans.zrem(semaphore_key_prefix, id);
        trans.zrem(owner, id);
        trans.exec();

        return null;
    }

    private boolean releaseFairSemaphore(Jedis conn, String id) {
        Transaction trans = conn.multi();
        trans.zrem(semaphore_key_prefix, id);
        trans.zrem(semaphore_key_prefix + ":owner", id);
        List<Object> results = trans.exec();

        Long result = (Long) results.get(results.size() - 1);
        return result ==1;
    }
}
